
// only if the Inst Buffer is ready , the IFU ADDR Gen can work 

module frv_ifu_addrgen (
    input                   clk             ,
    input                   rst_n           ,
    // Program Downloader reset
    input                   pd_rst          ,
    // Branch Prediction 
    input [31:0]            bp_taddr        ,
    input                   bp_branch_taken ,
    // Exception Interface 
    input                   exp_flush       ,               
    input [31:0]            exp_taddr       ,               
    // downstream modoule control
    input                   bru_flush       ,
    input [31:0]            bru_btb_taddr   ,           
    input                   ib_ready        ,

    output                  imem_req        ,
    output [31:0]           imem_addr       
);


wire [31:0]           pc_data,pc_data_nxt;

wire [31:0]           inst_addr,inst_addr_nxt;
wire                  iaddr_vld,iaddr_vld_nxt;

wire                  ifetch_en;

wire [31:0] target_addr  = pd_rst    ? 32'h8000_0000 :
                           exp_flush ? exp_taddr : 
                           bru_flush ? bru_btb_taddr  :
                           bp_branch_taken ? bp_taddr :
                           pc_data ;

assign pc_data_nxt = target_addr + 4;

assign inst_addr_nxt = (exp_flush | bru_flush | bp_branch_taken) ? target_addr : pc_data;

assign iaddr_vld_nxt = ib_ready && ~pd_rst;

assign ifetch_en = ib_ready && ~pd_rst;

// Port Connect
assign imem_req  = iaddr_vld;
assign imem_addr = inst_addr;

//DFFs
dffr #(32,32'h8000_0000 + 4) pc_data_ff(clk,rst_n,ifetch_en,pc_data_nxt,pc_data);
dffr #(32,32'h8000_0000)     inst_addr_ff(clk,rst_n,ifetch_en,inst_addr_nxt,inst_addr);
dffr #(1)                     iaddr_vld_ff(clk,rst_n,ifetch_en,iaddr_vld_nxt,iaddr_vld);


endmodule


